home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AOL File Library: 2,801 to 2,900
/
aol-file-protocol-4400-2801-to-2900.zip
/
AOLDLs
/
C++ Files Library
/
SK (Sockects) 1.4.1 r2
/
SK v1.4.1 r2.sit
/
SK 1.4.1 r2
/
SK
/
SK Sources
/
SK_UDP.cc
< prev
next >
Wrap
Text File
|
1994-06-13
|
19KB
|
775 lines
/***************************************************************************
*
*
* Copyright ⌐ 1992-1994 Matthias Neeracher and the Decision Systems Group
*
* Permission is granted to anyone to use this software for any purpose on
* any computer system, and to redistribute it freely, subject to the
* following restrictions:
*
* 1) The authors and the Decision Systems Group are not responsible for
* the direct or indirect consequences of use of this software, no matter
* how awful, even if they arise from defects in the software itself.
* This restriction applies to the use of this and any derived source code
* and also to the use of all binary produced from this and any derived
* source code.
* 2) The origin and copyrights of this software must not be misrepresented,
* either by explicit claim or by omission or alteration of copyright or
* authorship header information in this file or in any derived file.
* 3) Altered or derived versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
*
* We encourage users of this software to provide feedback, bug fixes,
* and enhancements to the authors for incorporation into future releases.
*
* ==========================================================================
*
* FILE: SK_INET.cc
*
* AUTHOR: Matthias Neeracher and Stephan Deibel
*
* CREATION DATE: 12Aug92
*
* VERSION: 13Jun94
*
* DESCRIPTION:
*
* UDP datagram sockets implementation
*
* NOTES:
*
* 0) This code was derived from Matthias Neerarcher's GUSI 1.1.0 and
* the socket library written by Charlie Reiman (creiman@ncsa.uiuc.edu)
* and Tom Milligan (milligan@madhaus.utcs.utoronto.ca); Copyrights
* are subject to this origin.
*
* MODIFICATIONS:
* --------------------------------------------------------------------------
* Date Name Description of modification
* --------------------------------------------------------------------------
*
* 16Aug92 MN Split off
* 25Aug92 MN Started putting some real work in
* 14Sep92 MN select() didn't return enough goodies.
* 13Jul93 SD Port to THINK C++ 6.0
* 21Jul93 SD Subsetted to only TCP/UDP, applied DSG naming
* conventions and commenting guidelines, and
* changed name to "SK" for clear distinction from
* the GUSI code from which this was derived
* 13Jun94 SD Updated based on relevant changes to GUSI (through 1.4.1)
*
*/
#include "SK_INET_P.hh"
/**************************************************************************/
/**************************************************************************/
/* Completion procedures */
// Need to declare all completion procedures a "C" routines and not "C++"
// routines due to a bug in the THINK C++ 6.0 compiler.
extern "C" {
/*************************************************************************** *
* FUNCTION:
*
* udp_flush_read_ahead_done
*
* DESCRIPTION:
*
* Flush read-ahead completion procedure
*
* PARAMETERS:
*
* CSK_AnnotatedPB * -- Parameter block associated with completed flush read ahead
*
*/
void udp_flush_read_ahead_done(CSK_AnnotatedPB *pb)
{
UDPiopb * udp = pb->UDP();
// Check for nasty error that once plagued us (will be removed eventually)
ASSERT(udp->ioResult != inProgress);
}
/*************************************************************************** *
* FUNCTION:
*
* udp_read_ahead_done
*
* DESCRIPTION:
*
* Read-ahead completion procedure
*
* PARAMETERS:
*
* CSK_AnnotatedPB * -- Parameter block associated with completed read ahead
*
*/
void udp_read_ahead_done(CSK_AnnotatedPB *pb)
{
CSK_UDPSocket * sock = (CSK_UDPSocket *) pb->Owner();
UDPiopb * udp = pb->UDP();
if (!udp->ioResult) {
sock->fReceiveBuf = udp->csParam.receive.rcvBuff;
sock->fBytesReceived = udp->csParam.receive.rcvBuffLen;
} else {
sock->fReceiveBuf = nil;
sock->fBytesReceived = 0;
}
sock->fLastAsyncErr = udp->ioResult;
sock->fPeerSocketAddress.sin_len = sizeof(struct sockaddr_in);
sock->fPeerSocketAddress.sin_family = AF_INET;
sock->fPeerSocketAddress.sin_addr.s_addr = udp->csParam.receive.remoteHost;
sock->fPeerSocketAddress.sin_port = udp->csParam.receive.remotePort;
// Check for nasty error that once plagued us (will be removed eventually)
ASSERT(udp->ioResult != inProgress);
}
/*************************************************************************** *
* FUNCTION:
*
* udp_send_done
*
* DESCRIPTION:
*
* UDP send completion procedure
*
* PARAMETERS:
*
* CSK_AnnotatedPB * -- Parameter block associated with completed send
*
*/
void udp_send_done(CSK_AnnotatedPB *pb)
{
UDPiopb * udp = pb->UDP();
((SKt_MiniWds *)udp->csParam.send.wdsPtr)->terminus = udp->ioResult;
((SKt_MiniWds *)udp->csParam.send.wdsPtr)->ptr = nil;
// Check for nasty error that once plagued us (will be removed eventually)
ASSERT(udp->ioResult != inProgress);
}
} /* extern "C" */
/**************************************************************************/
/**************************************************************************/
/* CSK_UDPSocket members */
/*************************************************************************** *
* FUNCTION:
*
* CSK_UDPSocket::CSK_UDPSocket
*
* DESCRIPTION:
*
* Constructor for this class
*
*/
CSK_UDPSocket::CSK_UDPSocket()
: CSK_INETSocket()
{
fSocketState = SKk_STATE_NO_STREAM;
}
/*************************************************************************** *
* FUNCTION:
*
* CSK_UDPSocket::CSK_UDPSocket
*
* DESCRIPTION:
*
* Constructor for this class
*
* PARAMETERS:
*
* StreamPtr -- The stream to use with this UDP socket
*
*/
CSK_UDPSocket::CSK_UDPSocket(StreamPtr stream)
: CSK_INETSocket(stream)
{
OSErr err;
UDPiopb * pb;
pb = GetPB();
pb->ioCompletion = UDPIOCompletionProc(udp_read_ahead_done);
pb->csCode = UDPRead;
pb->csParam.receive.timeOut = 0 /* infinity */;
pb->csParam.receive.secondTimeStamp = 0 /* must be zero */;
/* We know that there is a read pending, so we make a synchronous call */
err = PBControlSync(ParmBlkPtr(pb));
// Check for nasty error that once plagued us (will be removed eventually)
ASSERT(pb->ioResult != inProgress);
if (err != 0)
SK_TCPError(err);
if (!pb->ioResult) {
fReceiveBuf = pb->csParam.receive.rcvBuff;
fBytesReceived = pb->csParam.receive.rcvBuffLen;
} else {
fReceiveBuf = nil;
fBytesReceived = 0;
}
fLastAsyncErr = pb->ioResult;
fPeerSocketAddress.sin_len = sizeof(struct sockaddr_in);
fPeerSocketAddress.sin_family = AF_INET;
fPeerSocketAddress.sin_addr.s_addr = pb->csParam.receive.remoteHost;
fPeerSocketAddress.sin_port = pb->csParam.receive.remotePort;
}
/*************************************************************************** *
* FUNCTION:
*
* CSK_UDPSocket::~CSK_UDPSocket
*
* DESCRIPTION:
*
* Destructor for this class
*
*/
CSK_UDPSocket::~CSK_UDPSocket()
{
UDPiopb * pb;
if (fSocketState == SKk_STATE_NO_STREAM)
return;
pb = GetPB();
pb->csCode = UDPRelease;
if (!PBControlSync(ParmBlkPtr(pb)))
DisposPtr(pb->csParam.create.rcvBuff);
// Check for nasty error that once plagued us (will be removed eventually)
ASSERT(pb->ioResult != inProgress);
}
/*************************************************************************** *
* FUNCTION:
*
* CSK_UDPSocket::GetPB
*
* DESCRIPTION:
*
* Get a UDP io parameter block for use with this UDP socket. The
* parameter block is obtained from the SKg_INETSockets domain object
* and is set up for use specifically with this socket.
*
* RETURNS:
*
* UDPiopb * -- The UDP io parameter block
*
*/
UDPiopb * CSK_UDPSocket::GetPB()
{
CSK_AnnotatedPB * pb = SKg_INETSockets.GetPB();
pb->UDP()->ioCRefNum = SKg_INETSockets.Driver();
pb->UDP()->udpStream = fStream;
pb->SetOwner(this);
return pb->UDP();
}
/*************************************************************************** *
* FUNCTION:
*
* CSK_UDPSocket::Available
*
* DESCRIPTION:
*
* Return number of bytes of unread data available on this socket
*
* RETURNS:
*
* u_long -- The number of unread bytes available
*
*/
unsigned long CSK_UDPSocket::Available()
{
return (fLastAsyncErr == inProgress) ? 0 : fBytesReceived;
}
/*************************************************************************** *
* FUNCTION:
*
* CSK_UDPSocket::NewStream
*
* DESCRIPTION:
*
* ???
*
* RETURNS:
*
* int -- Error value (0 = no error)
*
*/
int CSK_UDPSocket::NewStream()
{
OSErr err;
UDPiopb * pb;
pb = GetPB();
pb->csCode = UDPCreate;
pb->csParam.create.rcvBuff = (char *)NewPtr(SKk_StreamBufferSize);
pb->csParam.create.rcvBuffLen = SKk_StreamBufferSize;
pb->csParam.create.notifyProc = NULL;
pb->csParam.create.localPort = fMySocketAddress.sin_port;
err = PBControlSync(ParmBlkPtr(pb));
// Check for nasty error that once plagued us (will be removed eventually)
ASSERT(pb->ioResult != inProgress);
if (err != 0)
return SK_TCPError(err);
fStream = pb->udpStream;
fMySocketAddress.sin_port = pb->csParam.create.localPort;
fSocketState = SKk_STATE_UNCONNECTED;
fBytesReceived = 0;
fReceiveBuf = nil;
fLastAsyncErr = inProgress;
return ReadAhead();
}
/*************************************************************************** *
* FUNCTION:
*
* CSK_UDPSocket::FlushReadAhead
*
* DESCRIPTION:
*
* Flush the read-ahead buffer for this UDP socket
*
* RETURNS:
*
* int -- Error value (0 = no error)
*
*/
int CSK_UDPSocket::FlushReadAhead()
{
OSErr err;
UDPiopb * pb;
/* flush the read-ahead buffer if its not from our new friend */
pb = GetPB();
pb->ioCompletion = UDPIOCompletionProc(udp_flush_read_ahead_done);
pb->csCode = UDPBfrReturn;
pb->csParam.receive.rcvBuff = fReceiveBuf;
fReceiveBuf = nil;
fBytesReceived = 0;
err = PBControlAsync(ParmBlkPtr(pb));
if (err != 0)
return SK_TCPError(err);
else
return 0;
}
/*************************************************************************** *
* FUNCTION:
*
* CSK_UDPSocket::ReadAhead
*
* DESCRIPTION:
*
* Start asyncronous read-ahead on this UDP socket
*
* RETURNS:
*
* int -- Error value (0 = no error)
*
*/
int CSK_UDPSocket::ReadAhead()
{
OSErr err;
UDPiopb * pb;
pb = GetPB();
pb->ioCompletion = UDPIOCompletionProc(udp_read_ahead_done);
pb->csCode = UDPRead;
pb->csParam.receive.timeOut = 0 /* infinity */;
pb->csParam.receive.secondTimeStamp = 0 /* must be zero */;
fLastAsyncErr = 1;
err = PBControlAsync(ParmBlkPtr(pb));
if (err != 0)
return SK_TCPError(fLastAsyncErr = err);
return 0;
}
/*************************************************************************** *
* FUNCTION:
*
* CSK_UDPSocket::getsockname
*
* DESCRIPTION:
*
* Returns the current name for the given socket.
*
* PARAMETERS:
*
* void * -- Buffer space for returned name
* int * -- Buffer space for returned name length (should contain
* maximum allowable return length initially)
*
* RETURNS
*
* int -- 0 upon success; -1 upon failure
*
* The name and name length are returned in the provided buffer space.
*
*/
int CSK_UDPSocket::getsockname(void *name, int *namelen)
{
if (fSocketState == SKk_STATE_NO_STREAM)
if (NewStream())
return -1;
return CSK_INETSocket::getsockname(name, namelen);
}
/*************************************************************************** *
* FUNCTION:
*
* CSK_UDPSocket::connect
*
* DESCRIPTION:
*
* Initiate a connection on a MacTCP socket.
*
* This call specifies the address to which datagrams
* are to be sent, and the only address from which datagrams
* are to be received.
*
* PARAMETERS:
*
* void * -- The internet address to connect to
* int -- The length of the above internet address structure
*
* RETURNS:
*
* If the connection or binding succeeds, then 0 is returned.
* Otherwise a -1 is returned, and a more specific error code
* is stored in errno:
*
* EAFNOSUPPORT The address family in addr is not AF_INET.
*
* EHOSTUNREACH The TCP connection came up half-way and
* then failed.
*
* NOTES:
*
* UDP sockets may use connect() multiple times to change
* their association. UDP sockets may dissolve the association
* by connecting to an invalid address, such as a null
* address.
*
*/
int CSK_UDPSocket::connect(void * address, int addrlen)
{
struct sockaddr_in * addr = (struct sockaddr_in *) address;
if (addrlen != sizeof(struct sockaddr_in))
return SK_Error(EINVAL);
if (addr->sin_family != AF_INET)
return SK_Error(EAFNOSUPPORT);
/* make the stream if its not made already */
if (fSocketState == SKk_STATE_NO_STREAM) {
if (NewStream())
return -1;
} else if (fReceiveBuf)
if (FlushReadAhead())
return -1;
/* record our peer */
fPeerSocketAddress.sin_len = sizeof(struct sockaddr_in);
fPeerSocketAddress.sin_addr.s_addr = addr->sin_addr.s_addr;
fPeerSocketAddress.sin_port = addr->sin_port;
fPeerSocketAddress.sin_family = AF_INET;
fSocketState = SKk_STATE_CONNECTED;
return 0;
}
/*************************************************************************** *
* FUNCTION:
*
* CSK_UDPSocket::recvfrom
*
* DESCRIPTION:
*
* recvfrom() attempts to receive a message (ie a datagram) on this socket
*
* PARAMETERS:
*
* void * -- Pointer to buffer for returned bytes
* int -- Maximum number of bytes to read
* int -- unused
* void * -- Pointer to memory for return value (address of sender)
* int * -- Pointer to memory for length of return value
*
* RETURNS:
*
* int -- Error return (0 = no error), -1 = error in which case
* a more specific error code is stored in the global errno:
*
* ESHUTDOWN The socket has been shutdown for receive operations.
*
* The bytes received are read into the given buffer.
*
* The internet address of the caller and the length of that address
* are placed into the last two parameters (void * and int).
*
* NOTES:
*
* Typically, read() is used with a TCP stream and recv() with
* UDP where the idea of a message makes more sense. But in fact,
* read() and recv() are equivalent.
*
* Regardless of non-blocking status, if less data is available
* than has been requested, only that much data is returned.
*
* If the socket is marked for non-blocking I/O, and the socket
* is empty, the operation will fail with the error EWOULDBLOCK.
* Otherwise, the operation will block until data is available
* or an error occurs.
*
* A return value of zero indicates that the stream has been
* closed and all data has already been read. ie. end-of-file.
*
*/
int CSK_UDPSocket::recvfrom(void * buffer, int buflen, int, void * from, int * fromlen)
{
/* make the stream if its not made already */
if (fSocketState == SKk_STATE_NO_STREAM)
if (NewStream())
return -1;
/* dont block a non-blocking socket */
if (fNonBlocking && fLastAsyncErr == 1)
return SK_Error(EWOULDBLOCK);
SPIN(fLastAsyncErr == 1, SKk_DGRAM_READ,0);
if (fLastAsyncErr!=noErr)
return SK_TCPError(fLastAsyncErr);
/* return the data to the user - truncate the packet if necessary */
buflen = MIN(buflen,fBytesReceived);
BlockMove(fReceiveBuf, buffer, buflen);
if (from && *fromlen >= sizeof(struct sockaddr_in)) {
*(struct sockaddr_in *) from = fPeerSocketAddress;
*fromlen = sizeof (struct sockaddr_in);
}
/* continue the read-ahead - errors which occur */
/* here will show up next time around */
FlushReadAhead();
ReadAhead();
return buflen;
}
/*************************************************************************** *
* FUNCTION:
*
* CSK_UDPSocket::sendto
*
* DESCRIPTION:
*
* sendto() is used to transmit a message from this socket to another socket.
*
* PARAMETERS:
*
* void * -- Pointer to buffer containing bytes to send
* int -- The number of bytes to send
* int -- Flags (???)
* void * -- Pointer to internet address to send to
* int -- Length of above internet address structure
*
* RETURNS:
*
* This call returns the number of bytes sent, or -1 if an error occurred,
* in which case the global errno contains a more detailed error value:
*
* EINVAL The sum of the iov_len values in the iov array was
* greater than 65535 (TCP) or 65507 (UDP) or there
* were too many entries in the array (16 for TCP or
* 6 for UDP).
*
* ESHUTDOWN The socket has been shutdown for send operations.
*
* EMSGSIZE The message is too big to send in one datagram. (UDP)
*
* ENOBUFS The transmit queue is full. (UDP)
*
* The bytes received are read into the given buffer.
*
* NOTES:
*
* Typically, write() is used with a TCP stream and send() with
* UDP where the idea of a message makes more sense. But in fact,
* write() and send() are equivalent.
*
* Write() and send() operations are not considered complete
* until all data has been sent and acknowledged.
*
* The message must be short enough to fit into one datagram.
*
* Buffer space must be available to hold the message to be
* transmitted, regardless of its non-blocking I/O state.
*
*/
int CSK_UDPSocket::sendto(void * buffer, int count, int, void * to, int)
{
SKt_MiniWds awds;
OSErr err;
UDPiopb * pb;
/* make the stream if its not made already */
if (fSocketState == SKk_STATE_NO_STREAM)
if (NewStream())
return -1;
if (count > SKk_UDPMaxMessageSize)
return SK_Error(EMSGSIZE);
awds.terminus = 0;
awds.length = count;
awds.ptr = (char *) buffer;
// if no address passed, hope we have one already in fPeerSocketAddress field
if (to == NULL)
if (fPeerSocketAddress.sin_len)
to = &fPeerSocketAddress;
else
return SK_Error(EHOSTUNREACH);
pb = GetPB();
pb->ioCompletion = UDPIOCompletionProc(udp_send_done);
pb->csCode = UDPWrite;
pb->csParam.send.remoteHost = ((struct sockaddr_in *)to)->sin_addr.s_addr;
pb->csParam.send.remotePort = ((struct sockaddr_in *)to)->sin_port;
pb->csParam.send.wdsPtr = (Ptr)&awds;
pb->csParam.send.checkSum = true;
pb->csParam.send.sendLength = 0 /* must be zero */;
err = PBControlAsync(ParmBlkPtr(pb));
if (err != 0)
return SK_TCPError(err);
// get sneaky. compl. proc sets ptr to nil on completion, and puts result code in
// terminus field.
SPIN(awds.ptr != NULL, SKk_DGRAM_WRITE, count);
if (awds.terminus < 0)
return SK_TCPError(awds.terminus);
else
return count;
}
/*************************************************************************** *
* FUNCTION:
*
* CSK_UDPSocket::select
*
* DESCRIPTION:
*
* Select read/write/exception abilities for this socket (???)
*
* PARAMETERS:
*
* Boolean * -- Can read (???)
* Boolean * -- Can write (???)
* Boolean * -- Exception (???)
*
* RETURNS:
*
* int -- ???
*
*/
int CSK_UDPSocket::select(Boolean * canRead, Boolean * canWrite, Boolean * )
{
int goodies = 0;
if (canRead || canWrite)
if (fSocketState == SKk_STATE_NO_STREAM)
NewStream();
if (canRead)
if (fLastAsyncErr != 1) {
*canRead = true;
++goodies;
}
if (canWrite) {
*canWrite = true;
++goodies;
}
return goodies;
}
/* end of SK_UCP.cc */